Tutorials
Getting started
Chart interface
Web components
Chart internals
Data integration
Customization
Frameworks and bundlers
Mobile development
Plug-ins
Compact Chart
Troubleshooting
Glossary
Reference
JSFiddles

Web Component Interface

The ChartIQ sample templates, located in chartiq/examples/templates, utilize W3C-standard web components. These components allow you to create custom tags with built-in programming logic, enabling you to personalize your interfaces.

By leveraging the Web Components specification, you can develop custom tags tailored to your needs. The library file componentUI.js enhances functionality by offering basic data-binding capabilities and a streamlined infrastructure for constructing interfaces with web components.

See the complete list of ChartIQ web components.

Newly Rearchitected ChartIQ Web Components

ChartIQ Version 9.1.0 introduced a significant architectural update to our web components, which now support the use of dynamic and reactive attributes. This enhancement allows developers to easily customize and manipulate these web components, eliminating the need for invoking API methods that were previously required.

  • Our web components can now emit events when their attributes change.
    • For example, developers can easily listen to and handle these events using custom React hooks, which provide a flexible and efficient way to respond to attribute changes.
  • Conversely, you can now send an event or change in state to a component by changing an attribute, allowing the component to react to this change. Previously, achieving this effect would require calling a function, which was more difficult and prone to error.
  • A component can listen for these events even when it is not active or visible, making it particularly useful when changing themes.
  • Similar to the way React manages state, events can be saved in local storage and then picked up by an attribute change when a particular component loads again.

These changes update our web component architecture to align with the latest patterns in framework development, providing developers, especially those working in frameworks like React, with a more modern and customizable library.

In addition to the dynamic and reactive attribute tags, the web component architecture offers several other benefits. These benefits include modularity, which makes the components flexible, reusable, and decoupled. It also enhances testing and debugging capabilities, and improves readability for developers, particularly those working with frameworks like React.

The updated web components also represent a notable achievement for ChartIQ as we significantly enhanced accessibility for visually impaired users. By ensuring comprehensive screen reader accessibility for menu options, drawing tools, pop-ups, and dialogues, we have made significant progress toward inclusivity and usability.

Note: Those using older versions of the library or legacy web components will not have the same features.

Legacy web components and documentation

All tutorials and API documentation from before the rearchitecting of our web components are available on the ChartIQ Legacy Documentation site, which is up-to-date with Version 8.9.0.

The latest versions of the library still include legacy web components and are found in chartiq/js/components-legacy.js. However, if you plan to use them with Version 9.1.0 or later, there are important limitations to consider:

  • You cannot mix and match old and new components. It's all or nothing.
  • You cannot use legacy components with current html templates (i.e. templates from 9.1.0 and newer versions), and vice-versa. You must use your own custom or legacy template with the legacy components.

See the backwards compatibility instructions.

Web components 101

1: Web components are custom tags

Web components, such as ChartIQ tags, are self-contained and start as "custom tags" that can be named however you like, but they must include a hyphen. ChartIQ tags, for example, begin with "cq-".

Example ChartIQ web component:

Note: ChartIQ sample templates contain multiple cq-dialog components. To allow for specific component selection in the following examples, we have added an ID. Additionally, ChartIQ components must be within the cq-context tags in order for the web components to have control of the chart.

<cq-context>
	<cq-dialog id="myDialog"><cq-dialog>
</cq-context>

Web components, like other tags, can be referenced using DOM methods such as querySelector() and getElementById(), and styled using CSS.

Starting with Version 9.1.2, each ChartIQ web component with custom styling has its own dedicated SASS file in the css/webcomponents/ folder. For instructions on custom styling, see the CSS Overview tutorial.

Note: One difference is that, unlike a div, custom tags default to display: inline rather than display: block.

Example: Manipulating web components:

<style>
	cq-dialog#myDialog {
		background-color: black;
	}
</style>
<script>
	const dialogBox = document.getElementById("myDialog");
	dialogBox.setAttribute('cq-title','Lorem ipsum');
	dialogBox.open();
</script>

2: Web components are JavaScript objects

Web components must implement the HTMLElement interface, so they are typically created using "inheritance". Since web components are JavaScript objects, it is easy to make them do things. Inside a component, this refers to the component itself. Thus, with a web component, you can combine HTML operations and business logic (such as calculating a study or saving an instance of the crosshairs to local storage) in one place.

Example: A component comes alive:

dialogBox.updateDialogTitle = function() {
	this.setAttribute("cq-title","Hello world!");
};

dialogBox.updateDialogTitle();

One of the tough problems for most frameworks is making components work together. Usually this results in tight coupling, which makes most single page applications (SPA) increasingly difficult to manage as they grow in scale. Web components live in the DOM, which means that they are automatically organized and that selectors can be used to link them.


3: Web components observe life-cycle events

With the release of v9.1.0, our web components have been rearchitected to support a more modern approach by handling key lifecycle events. These events include connectedCallback(), disconnectedCallback(), adoptedCallback(), and attributeChangedCallback(). These lifecycle callbacks have been implemented to better align our web components with industry standards, making development and customization easier for developers.

Legacy web components from versions of the library older than 9.1.0 govern their life-cycles using callbacks that each legacy component automatically provides. Please consult the legacy documentation for more on how these work.


4: Web components can use templates

The template tag provides a clean, easy way to build dynamic content. Content inside a template tag is ignored by the browser, but is still visible when you inspect the HTML.

Example: Let's create a list:

<style>
	cq-dialog#myDialog {
		top: 30%;
		left: 30%;
		transform: translate(-50%, -50%)
	}
</style>

<cq-dialog id="myDialog">
	<template item>
		<li></li>
	</template>
	<ul></ul>
</cq-dialog>

<script>
const dialogArray = [
  "Dialog Item 1",
  "Dialog Item 2",
  "Dialog Item 3",
  "Dialog Item 4",
  "Dialog Item 5",
];

const dialogBox = document.getElementById("myDialog");
dialogBox.createListItem = function (str) {
  const ul = this.node.find("ul");
  const template = this.node.find("template[item]");
  let newItem = CIQ.UI.makeFromTemplate(template)[0];
  newItem.innerText = str;
	// newItem.setAttribute('stxtap', 'handleClick()') <-- This will be used in a later example
  ul.append(newItem);
};

dialogArray.forEach((item) => {
  dialogBox.createListItem(item);
});

setTimeout(() => dialogBox.open());
</script>

In the example above we use a couple of patterns.

  • First we create a template tag and fill it with the raw html that we want to use to build list items. We've given it an attribute name to make it easy to find with a selector.
    Note: if you only have a single template in your web component you don't need an attribute to reference.
  • Inside of our component logic, once we've found our template within the DOM, we use the convenience method makeFromTemplate to convert the template into live HTML.
  • Finally, we add the new HTML into the DOM where we want it.

This is an "imperative" approach to dynamic content, which is simple to follow. However, the component infrastructure does not support a "declarative" (data binding) approach. For data binding, you can explore other templating libraries available.


5: Web components are composable

You can compose web components together with other web components. This can be done at two levels. You can do this within a single HTML page.

Example: Compose one component with another:

<cq-dialog>
	<cq-close></cq-close>
</cq-dialog>

In this example, developers can easily customize the web component by modifying the HTML. It is important to write the component "defensively" (without making too many assumptions about its content). This approach allows for the creation of ready-made components that can still be customized.

Additionally, web components can be designed to be "opaque," meaning that their contents are visible but not easily changed. This is done by placing the components in a separate file and importing them when needed.


Working With The ChartIQ Web Component Framework

Getting Started

Loading the Framework

To use the ChartIQ Web Component Framework you may include the following third party libraries:

  • perfect-scrollbar.esm.js (used to style scrolling components such as menus).

Then include componentUI.js, which is part of the ChartIQ library. sample-template-advanced.html and sample-template-basic.html contain example code.

HTML tags that begin with "cq-" are web components that become enabled when you include componentUI.js.

Setting Up the Framework

You must set up the cq-context element before you can use any of the library's web components.

The cq-context element is a special element used by the chart library web components. It wraps all library web components and holds a reference to a specified ChartEngine instance. This enables the web components to have direct control over the chart.

The cq-context can be defined in one of two ways: a custom attribute or a custom element.

Custom Attribute:

Use this method when placing the chart in an existing html layout.

<div cq-context>
	<!-- Chart & Chart UI Goes Here -->
</div>
Custom Element:

Use this method to define the container element more explicitly.

<cq-context>
	<!-- Chart & Chart UI Goes Here -->
</cq-context>

To host multiple charts on a screen you should set up a cq-context element for each ChartEngine instance.

Modifying the default configurations

The ChartIQ library includes a default configuration object that establishes a basic chart configuration.

When creating your chart and making modifications to suit your needs, it is recommended to make changes to the configuration object directly in your template before calling config.createChart(), rather than modifying the default configuration object. Modifying defaultConfiguration.js may result in issues when upgrading to newer versions.

Examples:

The below code pasted into one of our sample templates will change the weekly periodicity to '2-day' periodicity. See the CIQ.UI.Layout#setPeriodicity API docs for more information.

const newPeriodicityObj = { type: "item", label: "2 D", tap: "Layout.setPeriodicity", value: [2, 1, "day"] };
config.menus.period.content[1] = newPeriodicityObj;

Changes the initial symbol of the chart.

config.initialSymbol.symbol = "XYZ";

See the Chart Configuration Tutorial to learn more about the default configuration object.

Creating Web Components: BaseComponent and ContextTag

In order to interact with the UI framework, components should be derived from the BaseComponent class in componentUI.js. This allows components to utilize the built-in data binding and key capture capabilities.

To interact with a chart, components should be derived from ContextTag. This tag automatically locates the cq-context component that is parent to the tag, ensuring that the context knows about the tag and vice versa. By using this.context.stx, components can reliably provide a reference to the chart object.

A third type of component called a DialogContentTag can be used for components that potentially need to interact with multiple charts. Dialogs are a perfect example, where a single dialog on a page may interact with any chart on the page depending on which button the user pressed. In this case this.context.stx changes depending on the state of the tag.

Helpers

In addition to web components, the UI framework includes a set of classes called "Helpers". The job of a Helper is to bridge functionality between a component and a chart engine (i.e. Layout, StudyEdit). A Helper can also be used to implement data binding on a section of DOM that isn't componentized (i.e. StudyMenu).

Helpers are always associated with a particular chart context. They must be created in your JavaScript:

var context = new CIQ.UI.Context(stxx, document.querySelector("cq-context"));
var layout = new CIQ.UI.Layout(context);

Since Helpers do not live in the DOM, they rely on the context to connect them for data binding. They do this by advertising themselves with the method advertiseAs(). Generally, you don't need to worry about Helpers unless you need to add additional bindings. If so, we recommend extending the CIQ.UI.Layout prototype with additional methods.

Bindings

The UI framework uses attributes for binding. Three types of binding are supported:

  1. stxtap - User click/tap (or hits enter in an input tag)

    <div stxtap='handleClick()'> will call the method handleClick() when the user clicks/taps on that div tag. The framework will look for the nearest parent object that has that function.

    You can also target Helpers with this code <div stxtap='Layout.handleClick()'>. In this case, the nearest ContextTag will activate the binding, and use its context to find an associated Layout helper.

    Example, bindings are automatically associated with the nearest parent component:

    Let's add a toggle to the header that allows users to switch between day and night themes with a single click. The following will work in our sample templates.

    <!-- <div class="icon-toggles ciq-toggles"> -->
    <cq-toggle id="toggle"><div stxtap="changeTheme()">Toggle Theme</div></cq-toggle>
    <!-- </div> -->
    
    <script>
    const themeToggle = document.querySelector('#toggle');
    
    themeToggle.changeTheme = function () {
    const themeElement = document.querySelector('cq-themes') // find the cq-themes component
    let currentTheme = themeElement.getAttribute('theme') // store its current theme setting
    if (currentTheme === 'ciq-day') { // toggle between ciq-night and ciq-day
    	themeElement.setAttribute('theme', 'ciq-night')
    } else {
    	themeElement.setAttribute('theme', 'ciq-day')
    }
    }
    </script>
    
  2. stxbind - Keeps DOM in sync with the contents of a JavaScript variable

    Unlike more comprehensive data binding systems, stxbind defers the job of binding to a member call. For instance, <div stxbind='bindFunction()'> simply calls the method bindFunction() when the component is instantiated. It is the job of bindFunction() to monitor a JS variable and update the DOM.

    Example, establish a binding:

    In this simple example, stxbind is used to monitor and adjust the toggle's value attribute based on the current chart theme when the page reloads. This allows us to simplify the changeTheme function by utilizing a ternary operator.

    <script>
    themeToggle.bindFunction = function () {
    let currentTheme = document.querySelector('cq-themes').getAttribute('theme')
    if (currentTheme === 'ciq-day') this.value = true;
    }
    
    // Update to changeTheme function used above
    themeToggle.changeTheme = function () {
    const theme = document.querySelector('cq-themes')
    theme.setAttribute('theme', this.value ? 'ciq-night' : 'ciq-day');
    }
    </script>
    
    • You can also set up a property of an object to be observed using CIQ.UI.observeProperty. When the property value changes, a listener function is executed.
      Note: This method requires access to a chart engine.

    This example builds off of the previous example and uses the observeProperty method inside of our bindFunction. In this case, we are monitoring the cq-themes component, specifically its currentTheme. This example keeps the cq-toggle in sync with the current theme, regardless of how a user switches themes.

    <cq-toggle id="toggle"><div stxtap="changeTheme()"stxbind="bindFunction()"></div></cq-toggle> 
    
    <script>
    const themeToggle = document.querySelector('#toggle');
    const themeElement = document.querySelector('cq-themes')
    
    themeToggle.bindFunction = function (node) {
    const currentTheme = themeElement.theme;
    if (currentTheme === 'ciq-day') this.value = true; // updates value when page is refreshed
    CIQ.UI.observeProperty('currentTheme', themeElement, () => {
    	node.innerText = themeElement.currentTheme.replace(/^ciq-(\w+)/, "$1").toUpperCase();
    })
    }
    </script>
    
  3. stxsetget - Two-way binding

    stxsetget is a convenience method for adding both stxtap and stxbind with a single attribute. The main difference is that "set" and "get" are prepended to the attribute value when called. Two-way binding is used for instance when building the radio button display menu in sample-template-advanced.html.

    Of course, there is no restriction on including other data binding or templating engines if you have more demanding data binding needs.

Observing and modifying state

Attributes

ChartIQ web components provide observed attributes for dynamic customization and modification of component behavior and appearance, enabling enhanced UI customization beyond the native features in the ChartIQ library.

Below are some examples of web components and their attributes.

Web Component Attributes
cq-drawing-palette "view", "active-tool", "docked"
cq-dropdown "maximize", "noresize", "config"
cq-color-picker "cq-active","cq-colors"
cq-dialog "cq-title","cq-description", "cq-close-button"
cq-toggle "action", "config, "stxtap", "toggles", "tooltip"
cq-menu "binding", "config", "help-id", "icon", "reader", "responsive", "state", "text", etc...
Emitters

Web component emitters in the ChartIQ architecture allow for the transmission of events and changes in state through attribute tags. These events can be listened to using custom React hooks or other methods. By changing an attribute, components can react to the event or state change, providing a more modern and customizable library for developers.

Note: The name of the event being emitted is the name of the component but in UpperCamelCase. For instance, in the example below, the name of the event emitted by <cq-drawing-palette> is simply DrawingPalette. Copy/paste the below code into your console and then interact with the drawing palette to see its custom event details.

Example:

const palette = document.querySelector("cq-drawing-palette");

palette.addEventListener("DrawingPalette", (e) => {
	console.log("the drawing palette did something");
	console.log("this is what happened: ", e.detail);
});

Customizing HTML and CSS

Customizing the provided templates is really as easy as modifying the HTML and CSS. Simply delete a component from the HTML if you don't wish to use it. If you want to make it look different you can reorganize the HTML inside the component and modify the associated CSS.

The CSS used by the templates is actually built using SASS. The SASS is compiled into chartiq.css. You should never modify chartiq.css directly because this will make it very difficult to upgrade in the future. Instead, we recommend adding additional CSS in your own file and then including it after chartiq.css. All CSS values can be overridden in this manner. Following this approach will guarantee easy upgrades.

Example, overriding the font size of cq-show-range:

cq-show-range {
  font-size: 14px;
}
<link rel="stylesheet" type="text/css" href="chartiq/css/chartiq.css" />
<link rel="stylesheet" type="text/css" href="mycss.css" />

Note: An exception to this rule is if you wish to change the colors or fonts for the entire template. In this case, we recommend making a copy of css/chartiq.scss. Change the variables to contain the colors and styles that you prefer. Then use a SASS builder to generate a new chartiq.css file.

Component Specifics

Here are some examples of the commonly used web components found in our sample charts.

  • cq-toggle - creates a toggle div that can automatically be bound. See WebComponents.Toggle.

  • cq-clickable - creates an div that when clicked runs a method on a different component. See WebComponents.Clickable.

  • cq-dialog - creates a dialog that is centered on the screen. A cq-dialog should typically contain a component that is derived from CIQ.UI.DialogContentTag. Generally, you would call open() or close() on the inner content tag instead of interacting directly with the dialog. See WebComponents.Dialog.

Example, open a dialog:

<cq-dialog cq-title="Hello World" cq-close-button="false">
	<!-- insert your HTML here -->
</cq-dialog>
<script>
	document.querySelector("cq-dialog").open();
</script>
  • cq-menu - creates a dropdown menu. Menus appear when tapped or clicked (not hovered). As of version 9.1.0, cq-dropdown is generally created automatically within cq-menu, so you typically don't need to include it. The CSS for this component has been carefully constructed so that menuing is extremely lightweight. See WebComponents.Menu.

This example from sample-template-advanced gets configured via defaultConfiguration.js. Use it as a starting point for creating your menus.

<cq-menu
  class="nav-dropdown ciq-display"
  reader="Display"
  config="display"
  binding="Layout.chartType"
  icon
  help-id="display_dropdown"
  tooltip
></cq-menu>;
  • cq-color-picker - establishes a color picker component for the page. Only a single color picker exists on the page. It is relocated dynamically whenever it is opened. The color picker is triggered by a cq-swatch component which displays a clickable swatch of color. See WebComponents.ColorPicker.

See WebComponents.html for a full list of available components and their documentation.

Data Integration

Driver.Lookup (Symbol Search Engine)

The cq-lookup and cq-lookup-dialog tags require a Lookup.Driver helper to process "look ahead" (autocomplete) keystrokes and to fetch results. CIQ.ChartEngine.Driver.Lookup provides a default implementation that queries against ChartIQ's symbol server.

The default lookup driver is defined in examples/feeds/symbolLookupChartIQ.js and needs to be loaded to be available

To simplify the integration process, we suggest making a duplicate of the symbolLookupChartIQ.js file and customizing the CIQ.ChartEngine.Driver.Lookup.ChartIQ and CIQ.ChartEngine.Driver.Lookup.ChartIQ.prototype.acceptText functions according to your specific requirements. This approach allows you to maintain the core structure of our sample Lookup.Driver while tailoring it to your needs. By doing so, you can ensure a seamless transition and take advantage of the existing structure and functionality.

Note: When implementing your customization, the acceptText() method receives the user-entered text and any selected lookup filters. Results should be returned as an array of objects, each containing a data item (in whatever format you wish) and a display array with displayable values.

Example:

CIQ.ChartEngine.Driver.Lookup.ChartIQ = function (exchanges) {
	this.exchanges = exchanges;
	if (!this.exchanges)
	// Modify this array to suit the needs of your chart
		this.exchanges = [
			// Exchanges
		];
	this.url = // your URL;
	this.requestCounter = 0; //used to invalidate old requests
};

CIQ.ChartEngine.Driver.Lookup.ChartIQ.prototype.acceptText = function (
	text,
	filter,
	maxResults,
	cb
) {
	// your code here
}

NameValueStore

Some supplied web components require a name value store in order to persist their state across sessions. By default, the library comes with a NameValueStore implementation that uses the browser's localStorage. You can however create your own which could use a network service for persistence.

To use an alternative store, you should first create a class that conforms to the NameValueStore interface. This should implement get, set and remove methods.

Example, create a custom NameValueStore:

const MyNVS = {
	get: function(field, cb) {
		cb(null, result);
	},
	set: function(field, value, cb) {
		// set
	},
	remove: function(field, cb) {
		// remove
	}
};

Next, you will need to initialize the desired components with this NameValueStore.

cq-themes and cq-views currently use this interface to store values.

Example, initialize components with custom NameValueStore:

document.querySelector("cq-themes").initialize({
	builtInThemes: { "ciq-day": "Day" },
	nameValueStore: new MyNVS()
});

document.querySelector("cq-views").initialize({
	nameValueStore: new MyNVS()
});

Advanced Topics

KeystrokeHub

This is a singleton helper that manages keystrokes. In HTML, you would typically register for key events on an input tag. The KeystrokeHub handles the more complicated problem of handling keystrokes that are independent of input tags. Examples include global hotkeys, passing keystrokes to a chart, or navigating the menuing system with keys.

You must initialize a KeystrokeHub with JavaScript code and associate it with a context. (You can optionally dynamically associate the context by calling setContext()). The KeystrokeHub registers itself with the cq-ui-manager so that it is universally available.

Components receive keystrokes by registering "claims". The KeystrokeHub distributes keystrokes to all components who have staked a claim by calling their keyStroke() method. A component can then decide whether to act on the keystroke, and if so, return true so that no other component acts on the stroke. It is the responsibility of the component to decide whether it should act. For instance, cq-scroll components only act on cursor up, cursor down, and enter keystrokes. Furthermore, they only act on them if the component itself is visible.

If a keystroke is not claimed by any component then the KeystrokeHub will attempt to satisfy any global hotkeys by calling CIQ.UI.KeystrokeHub.defaultHotKeys(). A default implementation is provided in defaultConfiguration.js, but you have the option to override this prototype method if desired.

For both components as well as hotkeys, the default browser key code will be passed for most keys. For special keys, a string is passed to indicate the key that was pressed. For instance, "up" is passed when the cursor up key is pressed.

Lifts

From time to time, an interactive page runs into formatting constraints. A typical constraint might occur in dialogs, where interactive (pop-up) data is hidden by the edge of the dialog. The most common example of this is when implementing a select-box inside of a dialog. Native select-boxes are ugly, but custom select-boxes get cut off when inside dialogs.

By adding the cq-lift attribute to a tag, the cq-ui-manager will temporarily "lift" the tag outside of its container, freeing it of its bounding box. It does this by using absolute positioning. When the tag is acted upon, the lift is released, and the tag goes back into its dialog. To see an example of cq-lift in action, check out sample-template-multichart.html and inspect the periodicity dropdowns that are next to the current symbol.

containerExecute

This provides a convenient pattern for nested composable components. containerExecute will traverse up an ancestor tree looking for a component that contains a given method.

As an example, consider the tag cq-close tag. We would like to nest this tag arbitrarily inside any type of component and have it automatically close the parent component. But we might want to wrap it in some formatting, which decouples the tag in the DOM. In this circumstance, we have coded the cq-close component to emit a containerExecute that will call the close() method on the nearest parent that contains that method. So long as a tag implements this interface, cq-close can be nested inside.

An analogy is exception handling. Calling containerExecute is like throwing an exception. It will traverse up the stack until it finds a handler and then passes the message to that handler.

Resizables

Until recently, receiving resize events from DOM elements was not universally supported across browsers (only window resizing is an event in some browsers). In dynamic single page applications though, we frequently encounter interfaces that have DOM elements changing size based on user interactive. For instance, a menu may change in height as elements are added or removed.

Luckily, a workaround exists. The component library makes use of resize listeners that are based on the ResizeObserver API. Simply call CIQ.UI.addResizeListener(node, cb) to receive resize events. Note, be sure to call CIQ.UI.removeResizeListener(node) when cleaning up.

Additionally, any component registered this way will also have its resize() method called whenever the window itself is resized. This allows dialogs and menus to resize themselves accordingly.

jQuery

As of version 8.1.0, the web components no longer require jQuery. However, if you do choose to use jQuery, the components remain fully compatible. If you have implemented custom web components that rely on jQuery, you may need to include the deprecated.js module which contains the library's deprecated jQuery methods.

Data binding mechanics

You must call CIQ.UI.begin() in order to start data binding. This is primarily due to the potential for importing web components from other files. Once this has been called, components derived from BaseComponent automatically process their own data binding events.

You can dynamically create components and add them to the DOM. When components are attached, they are processed for data binding, but this processing only occurs once. If you remove a component and then add it elsewhere, the data bindings will not automatically change. In such cases, you need to call CIQ.UI.BaseComponent.buildReverseBindings and pass in the element that was moved or added after it was initially attached.

One of the complications with any framework is initialization. Many of the components require access to a cq-context, but there is no guarantee that the CIQ.UI.Context exists when those components are created. To address this, we leverage the DOM. Contexts are discovered by traversing the DOM. The actual CIQ.UI.Context implementation is stored in the cq-context tag as document.querySelector("cq-context").CIQ.UI.context. Each component also registers itself in document.querySelector("cq-context").CIQ.UI.Components[]. In this way, whoever gets created last (the component or the context) is responsible for linking themselves up. This is done by calling the setContext() method on the component itself.

Finally, this method of "implicit" data binding creates potential ambiguities. As a rule therefore, the framework requires that data bindings occur on their nearest ancestor component. In order to enforce this policy, and to ensure the existence of a full ancestor tree, bindings occur on the "nextTick" after a component is added to the DOM. This ensures that the DOM tree is fully established when all decisions about data binding occur.

Architectural Boundaries

While it is not a capability of the software, the architecture technically makes it possible (with additional syntax) for data bindings to target specific ancestors, or even unrelated components. However, since bindings occur at the time a component is added to the DOM, the architecture would not easily support "runtime" bindings - those that must be acted upon at the tick of user click.

CIQ.UI.observeProperty provides a convenient and lightweight observable mechanism, however, its limits must be understood. CIQ.UI.observeProperty binds directly to objects, not to a representation of an object chain. This means that a binding will not change if a parent object is replaced. This can lead to unintuitive results.

Example: Paste the following code into the console to see how CIQ.UI.observeProperty will 'observe' the dataSegment property and triggers a callback function when it updates.

CIQ.UI.observeProperty("dataSegment", stxx.chart, () =>
	console.log(stxx.chart.lastQuote.Close)
);

ModalTag

You can derive your components from ModalTag in order to automatically give them modal capabilities. This means that when you mouse over the tag, stx.modalBegin() and stx.modalEnd() are called, disabling mouse interaction with the associated chart. A ModalTag is typically used when superimposing a component on to a chart, often as a cq-marker. For this reason, ModalTag is derived from ContextTag and must have a cq-context in its ancestor tree.

Some of the ChartIQ web components that are derived from ModalTag are:

makeFromTemplate

Instantiating templates actually takes a fair amount of boilerplate, namely because they exist as a DocumentFragment and not as an actual DOM element. makeFromTemplate encapsulates that functionality so that you can easily create a template.

Next steps